<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\Plugin\AdminTenant\Logic;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Codec\Json;
use MoChat\App\Tenant\Contract\TenantContract;
use MoChat\App\Tenant\Contract\TenantMenuPackageContract;
use MoChat\App\User\Contract\UserContract;
use MoChat\Framework\Constants\ErrorCode;
use MoChat\Framework\Exception\CommonException;
use MoChat\Plugin\AdminTenant\Action\Admin\Traits\OrderTrait;
use MoChat\Plugin\AdminUser\Contract\AdminUserContract;
use MoChat\Plugin\AdminUser\Contract\AdminUserLevelContract;
use MoChat\Plugin\AdminWallet\Contract\AdminWalletContract;
use MoChat\Plugin\TenantOrder\Contract\TenantOrderContract;
use MoChat\Plugin\TenantProduct\Contract\TenantProductContract;
use MoChat\Plugin\TenantProduct\Contract\TenantProductSkuContract;
use MoChat\Plugin\TenantShop\Contract\TenantShopContract;
use Qbhy\HyperfAuth\AuthManager;
use Qbhy\SimpleJwt\JWTManager;

/**
 * 账户管理- 创建提交.
 *
 * Class StoreLogic
 */
class StoreLogic
{
    use OrderTrait;

    /**
     * @Inject
     * @var TenantContract
     */
    protected $tenantService;

    /**
     * @Inject
     * @var AdminUserContract
     */
    protected $adminUserService;

    /**
     * @Inject
     * @var TenantProductSkuContract
     */
    protected $tenantProductSkuService;

    /**
     * @Inject
     * @var AdminUserLevelContract
     */
    protected $adminUserLevelService;

    /**
     * @Inject
     * @var TenantProductContract
     */
    protected $tenantProductService;

    /**
     * @Inject
     * @var TenantShopContract
     */
    protected $tenantShopService;

    /**
     * @Inject
     * @var TenantOrderContract
     */
    protected $tenantOrderService;

    /**
     * @Inject
     * @var AdminWalletContract
     */
    protected $adminWalletService;

    /**
     * @Inject
     * @var UserContract
     */
    protected $userService;

    /**
     * @Inject
     * @var AuthManager
     */
    protected $authManager;

    /**
     * @Inject
     * @var TenantMenuPackageContract
     */
    protected $tenantMenuPackageService;

    /**
     * @Inject
     * @var StdoutLoggerInterface
     */
    private $logger;

    /**
     * @param array $params 请求参数
     * @return array 响应数组
     */
    public function handle(array $params, array $adminUser): array
    {
        // 验证手机号
        $phoneUser = $this->userService->getUserByPhone($params['phone'], ['id']);
        if (! empty($phoneUser)) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '手机号已存在，不可重复创建');
        }
        // 余额检查
        $order = $this->handleParamsOrder($params, $adminUser);

        // 数据操作
        Db::beginTransaction();
        try {
            // 数据入表
            $tenantId = $this->insertTenantData($params, $adminUser);
            // 订单&代理金币处理
            $this->order($params['skuId'], $order, $tenantId, $adminUser);
            // 创建租户权限
            $this->tenantService->updateTenantById($tenantId, ['role_menu' => $order['roleMenu']]);
            // 修改过期时间
            $this->tenantService->updateTenantById($tenantId, ['expired_at' => date('Y-m-d', strtotime("+{$order['cycle']} day"))]);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            $this->logger->error(sprintf('%s [%s] %s', '租户创建失败', date('Y-m-d H:i:s'), $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
            throw new CommonException(ErrorCode::SERVER_ERROR, $e->getMessage()); // '租户创建失败'
        }

        return [];
    }

    private function handleParamsOrder(array $params, array $adminUser)
    {
        $order = ['walletBalance' => 0, 'itemTotal' => 0, 'adjustmentTotal' => 0, 'total' => 0, 'stock' => 0, 'cycle' => 1, 'roleMenu' => '', 'userId' => $adminUser['id']];

        // 代理金币余额
        $user = $this->adminUserService->getAdminUserById($adminUser['id'], ['level', 'wallet_balance']);
        $order['walletBalance'] = $user['walletBalance'];

        // 套餐价格
        $sku = $this->tenantProductSkuService->getTenantProductSkuById($params['skuId'], ['attributes', 'price', 'stock']);
        $attributes = $this->tenantProductSkuService->getTenantProductSkuValuesById(explode(',', $sku['attributes']));
        foreach ($attributes as $v) {
            if ($v['attributeName'] === '服务周期') {
                $order['cycle'] = $v['attributeValue'];
            }
            if ($v['attributeName'] === '套餐功能') {
                $order['roleMenu'] = $v['attributeValue'];
            }
        }
        $order['stock'] = $sku['stock'];
        $order['itemTotal'] = $sku['price'] * 100;
        if ($sku['stock'] <= 0) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '套餐库存数量不足，请联系管理员');
        }

        if ($adminUser['isRoot'] === 1) {
            $priceRule = [
                'type' => 1,
                'discount' => 10,
            ];
        } else {
            // 代理扣币规则
            $level = $this->adminUserLevelService->getAdminUserLevelById($user['level'], ['price_rule']);

            if (! empty($level)) {
                $priceRule = Json::decode($level['priceRule']);
            }
        }

        // 统一折扣
        if (! empty($priceRule) && (int) $priceRule['type'] === 1) {
            $price = number_format($sku['price'] * $priceRule['discount'] / 10, 2, '.', '');
            $order['adjustmentTotal'] = ($sku['price'] - $price) * 100;
            $order['total'] = $price * 100;
            if ($user['walletBalance'] < $price) {
                throw new CommonException(ErrorCode::INVALID_PARAMS, '金币余额不足以支付租户套餐费用，请充值后创建');
            }
        }

        // 按套餐扣币
        elseif (! empty($priceRule) && (int) $priceRule['type'] === 2) {
            if (in_array($user['level'], array_column($priceRule['sku'], 'id'), true)) {
                foreach ($priceRule['sku'] as $item) {
                    if ($user['level'] == $item['id']) {
                        $price = $item['price'];
                        $order['adjustmentTotal'] = ($sku['price'] - $price) * 100;
                        $order['total'] = $price * 100;
                        if ($user['walletBalance'] < $item['price']) {
                            throw new CommonException(ErrorCode::INVALID_PARAMS, '金币余额不足以支付租户套餐费用，请充值后创建');
                        }
                    }
                }
            } else {
                $price = $sku['price'];
                $order['total'] = $price * 100;
                if ($user['walletBalance'] < $sku['price']) {
                    throw new CommonException(ErrorCode::INVALID_PARAMS, '金币余额不足以支付租户套餐费用，请充值后创建');
                }
            }
        }
        return $order;
    }

    private function insertTenantData(array $params, array $adminUser): int
    {
        $menuPackageId = $this->tenantMenuPackageService->getTenantMenuPackageBySkuId($params['skuId'], ['id']);
        $data = [
            'name' => $params['name'],
            'company_name' => $params['companyName'],
            'business_image' => Json::encode($params['businessImage']),
            'area' => $params['area'],
            'description' => $params['description'],
            'status' => 1,
            'max_employee' => $params['maxEmployee'],
            'max_corp' => $params['maxCorp'],
            'sku_id' => $params['skuId'],
            'role_menu' => '',
            'menu_package_id' => $menuPackageId['id'] ?? 0,
            'owner_id' => $adminUser['id'],
            'created_at' => date('Y-m-d H:i:s'),
        ];
        $tenantId = $this->tenantService->createTenant($data);
        // 生成初始密码
        $guard = $this->authManager->guard('jwt');
        /** @var JWTManager $jwt */
        $jwt = $guard->getJwtManager();

        $userData = [
            'name' => $params['name'],
            'phone' => $params['phone'],
            'gender' => 0,
            'status' => 1,
            'tenant_id' => $tenantId,
            'is_root' => 1,
            'password' => $jwt->getEncrypter()->signature($params['password']),
            'created_at' => date('Y-m-d H:i:s'),
        ];
        $rootId = $this->userService->createUser($userData);
        $this->tenantService->updateTenantById($tenantId, ['root_id' => $rootId]);
        return $tenantId;
    }
}
